/** Fichier déclarant une classe de production de bruit cohérent.
 *
 * Ce fichier contient la déclaration de la classe Bruit.
 *
 * @file Bruit.hpp
 * @author Johan "Solo" Luisier
 *
 * @date 2010
 */
#ifndef BRUIT_H
#define BRUIT_H

#include <iostream>

#include <vector>

#include <limits>

namespace Perlin
{

/**
 * Enumère les différents type d'interpolations possibles.
 */
enum InterpolFct
{
    /** @var Perlin::InterpolFct InterpolFct::Lineaire Interpolation linéaire,
     * à utiliser pour le debugging car le résultat n'est pas très esthétique.
     */
    Lineaire,
    /** @var Perlin::InterpolFct InterpolFct::Cosinus Interpolation par un
     * polynome de degré 1 en cos(x).
     */
    Cosinus,
    /** @var Perlin::InterpolFct InterpolFct::Cubique Interpolation cubique.
     */
    Cubique
};

/** Classe permettant de générer un bruit cohérent.
 *
 * Cette classe permet de produire un bruit cohérent, appelé bruit de
 * Perlin. Le principe est de superposer plusieurs harmoniques (du
 * type \f$ 2^i \f$) d'une perturbation fondamentale (avec des
 * amplitudes décroissantes). La fonction générant la perturbation
 * n'est pas complétement aléatoire, ce qui permet la
 * reproductibilité des résultats.
 *
 * On définit une période pour avoir un motif fondamental
 * périodique. Le fait que le motif soit périodique permet de
 * calculer un nombre limité de points.\n Ensuite on interpole la
 * valeur pour avoir une réponse continue.
 *
 * On superpose ensuite les ondes obtenues pour des fréquences
 * d'ordre \f$2^i\f$ et on diminue leut amplitudes par un facteur
 * \f$a^{2 \, i}\f$, avec \f$a \in \left[ 0, 1 \right] \f$.
 *
 * @author Johan "Solo" Luisier
 *
 * @date 2010
 *
 * @class Bruit "Bruit.hpp" "Bruit/Bruit.hpp"
 */
class Bruit
{
public:
    Bruit(const unsigned& periode = 300, const double& pers = .5,
          const unsigned& oct = 4, const InterpolFct& fct = Cubique);
    ~Bruit();
    void fonction(const InterpolFct& fct);
    void periode(const int& t);
    void persistance(const double& pers);
    void octaves(const unsigned& oct);
    
    double operator()(const int& x,
                      const int& y = std::numeric_limits< int >::max(),
                      const int& z = std::numeric_limits< int >::max()) const;
    double operator()(const double& x,
                      const double& y = std::numeric_limits< double >::max(),
                      const double& z = std::numeric_limits< double >::max()) const;
    
protected:
    /**
     * Facteur de normalisation (le bruit est un nombre "aléatoire"
     * dans l'intervalle \f$ \left[ 0, 1 \right] \f$). Corespond à la
     * valeur maximale d'un entier (\f$2^32 - 1\f$ pour un système 32
     * bits).
     */
    static const double normalisation;
    /**
     * Valeur de pi, utilisée pour l'interpolation Cosinus.
     */
    static const double Pi;
    /**
     * Type d'interpolation choisi.
     */
    InterpolFct Fonction;
    /**
     * Période de la perturbation fondamentale.
     */
    unsigned Periode;
    /**
     * Copie de la valeur de Periode, mais en double, utilisée pour
     * certaines opérations avec des nombres réels (évite des
     * conversions répétées).
     */
    double dPeriode;
    /**
     * Rapport entre l'amplitude de l'harmonique \f$2^{i-1}\f$ et
     * l'harmonique \f$2^i\f$.
     */
    double Persistance;
    /**
     * Détermine le nombre d'harmoniques à supertposer.
     */
    unsigned Octaves;
    
    double bruit(const int& x) const;
    double bruit(const int& x, const int& y) const;
    double bruit(const int& x, const int& y, const int& z) const;
    
    double inter(const std::vector< double >& pts,
                 const double& x) const;
    double inter(const std::vector< std::vector< double > >& pts,
                 const double& x, const double& y) const;
    double inter(const std::vector< std::vector< std::vector< double > > >& pts,
                 const double& x, const double& y, const double& z) const;
    
    double bruitInterpole(const double& x) const;
    double bruitInterpole(const double& x, const double& y) const;
    double bruitInterpole(const double& x, const double& y, const double& z) const;
    
private:
    double interLin1D(const std::vector< double >& pts, const double& x) const;
    double interLin2D(const std::vector< std::vector< double > >& pts,
                      const double& x, const double& y) const;
    double interLin3D(const std::vector< std::vector< std::vector< double > > >& pts,
                      const double& x, const double& y, const double& z) const;
    double interCub1D(const std::vector< double >& pts, const double& x) const;
    double interCub2D(const std::vector< std::vector< double > >& pts,
                      const double& x, const double& y) const;
    double interCub3D(const std::vector< std::vector< std::vector< double > > >& pts,
                      const double& x, const double& y, const double& z) const;
    
    double modulo(const double& nbr, const unsigned& base) const;
    //int puissance(const int& mantisse, const unsigned& exposant) const;
};
}

#endif // BRUIT_H
